#include "stdc/stdc++.h"
/**
 * 主题接口声明了RealSubject和Proxy的通用操作。只要客户端使用这个接口与RealSubject一起工作，
 * 就可以向其传递代理而不是真正的主题。
 */
class Subject
{
   public:
    virtual void Request() const = 0;
};
/**
 * RealSubject包含一些核心业务逻辑。通常，RealSubjects能够执行一些有用的工作，可能也很慢或敏感 -
 * 例如，纠正输入数据。代理可以解决这些问题，而无需更改RealSubject的代码。
 */
class RealSubject : public Subject
{
   public:
    void Request() const override
    {
        std::cout << "RealSubject: 处理请求。\n";
    }
};
/**
 * 代理具有与RealSubject相同的接口。
 */
class Proxy : public Subject
{
    /**
     * @var RealSubject
     */
   private:
    RealSubject *real_subject_;

    bool CheckAccess() const
    {
        // 这里应该进行一些真正的检查。
        std::cout << "Proxy: 在触发真正请求之前检查访问权限。\n";
        return true;
    }
    void LogAccess() const
    {
        std::cout << "Proxy: 记录请求时间。\n";
    }

    /**
     * 代理维护对RealSubject类对象的引用。它可以是懒加载的，也可以由客户端传递给代理。
     */
   public:
    Proxy(RealSubject *real_subject) : real_subject_(new RealSubject(*real_subject)) {}

    ~Proxy()
    {
        delete real_subject_;
    }
    /**
     * 代理模式最常见的应用包括延迟加载、缓存、控制访问、日志记录等。代理可以执行这些操作之一，
     * 然后根据结果将执行传递给链接的RealSubject对象中的相同方法。
     */
    void Request() const override
    {
        if (this->CheckAccess())
        {
            this->real_subject_->Request();
            this->LogAccess();
        }
    }
};
/**
 * 客户端代码应该通过Subject接口与所有对象（主题和代理）一起工作，以支持真实主题和代理。
 * 但在现实生活中，客户端大多数情况下直接与真实主题一起工作。在这种情况下，为了更轻松地实现模式，
 * 可以从真实主题的类中扩展代理。
 */
void ClientCode(const Subject &subject)
{
    // ...
    subject.Request();
    // ...
}

int main()
{
    std::cout << "Client: 使用真实主题执行客户端代码：\n";
    RealSubject *real_subject = new RealSubject;
    ClientCode(*real_subject);
    std::cout << "\n";
    std::cout << "Client: 使用代理执行相同的客户端代码：\n";
    Proxy *proxy = new Proxy(real_subject);
    ClientCode(*proxy);

    delete real_subject;
    delete proxy;
    return 0;
}